<!-- 本组件纯木偶组件，不要将业务逻辑写入此组件 -->

<script lang="ts">
  import { onMount, tick, createEventDispatcher } from 'svelte';

  import type { Ability } from '@vtuber/ThreeSDK';

  import useCaption from '../hooks/useCaption';
  import useEngine from '../hooks/useEngine';
  import usePlay from '../hooks/usePlay';
  import { errorReport } from '../utils/tools';
  const emit = createEventDispatcher();

  // 初始化引擎hooks
  let {
    initResult,
    sdkInitData,
    canvasRef,
    vtuberIndex,
    engine,
    humanInfo,
    initEngine,
    setVtuber,
    changeHumanInfo
  } = useEngine();

  export { sdkInitData, vtuberIndex, humanInfo };

  // 播放hooks
  let { value, playInit, wsHook, isWsHook, adjustVolume } = usePlay();
  const play = () => {
    if (!isWsHook(wsHook)) {
      return;
    }
    wsHook.play(
      false,
      (data) => {
        // 每句播放的时候，将上一次的播放语句，存放到已播放属性中
        captionData.removedValue += captionData.nowValue;
        captionData.nowValue = data.text;
        captionData.remainValue = captionData.remainValue.replace(captionData.nowValue, '');
        if (captionData.nowValue && caption.autoPosition) {
          tick().then(() => {
            highLightPosition(captionRef);
          });
        }
        emit('updateCaptionData', { captionData });
      },
      // @ts-ignore -此处是库的问题，这里有返回boolean值
      (isFinish: boolean) => {
        emit('updateFinish', { isFinish });
        if (isFinish) {
          captionData.nowValue = '';
        }
      }
    );
  };
  const stop = (stopAll: boolean = false) => {
    if (!isWsHook(wsHook)) {
      return;
    }
    wsHook.stop(stopAll);
  };
  const setVolume = (volume: number) => {
    adjustVolume(volume, engine);
  };
  export { value, play, stop, setVolume };
  $: {
    if (value) {
      playInit(value, engine, sdkInitData)
        .then((wsHookParams) => {
          wsHook = wsHookParams;
          play();
        })
        .catch((error) => {
          errorReport({
            name: `播放初始化失败 ${error.name}`,
            stack: error.stack,
            message: error.message
          });
        });
      captionData.remainValue = value;
      captionData.nowValue = '';
      captionData.removedValue = '';
    }
  }

  // 字幕hooks
  let { caption, highLightPosition, initCaption, captionData, originCaptionData } = useCaption();
  export { caption, originCaptionData };
  // 字幕dom
  let captionRef: HTMLElement | void;

  // 业务方传默认字幕
  $: {
    const { removedValue, remainValue } = originCaptionData;
    removedValue && (captionData.removedValue = removedValue);
    remainValue && (captionData.remainValue = remainValue);
    captionData.nowValue = '';
  }

  onMount(() => {
    tick()
      .then(() => initEngine(canvasRef, sdkInitData))
      .then((engineRes) => {
        if (engineRes) {
          engine = engineRes;
        }
      })
      .then(() =>
        Promise.all([setVtuber(vtuberIndex, engine as Ability), initCaption(engine as Ability)])
      )
      .then(() => changeHumanInfo(humanInfo, engine as Ability))
      .then(() => {
        initResult = true;
        emit('updateInitResult', { initResult: true });
      })
      .catch((error: Error) => {
        console.log(error);
        
        errorReport({
          name: `虚拟人初始化的时候错误 ${error?.name}`,
          message: error?.message,
          stack: error?.stack
        });
        emit('updateInitResult', { initResult: false });
      });
  });
</script>

{#if caption.show && value}
  <div class="caption {caption.className || ''}" bind:this={captionRef}>
    {captionData.removedValue}<span class="high-light">{captionData.nowValue}</span
    >{captionData.remainValue}
  </div>
{/if}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
  class="human-container"
  on:click={() => {
    emit('clickVtuber');
  }}
>
  <canvas class="{humanInfo.humanClassName || ''} human-ins" bind:this={canvasRef} />
  {#if initResult}
    <img
      src="//i.thsi.cn/staticS3/mobileweb-upload-static-server.img/m/atom/0b9a9f05-2544-435c-adcb-acde7587b46a.png"
      alt=""
      class="light {humanInfo.lightClass || ''}"
    />
    <img
      src="//i.thsi.cn/staticS3/mobileweb-upload-static-server.img/m/atom/39f8b03c-6e5c-47ed-808c-8c0bf5bf8eb0.png"
      alt=""
      class="stage {humanInfo.stageClass || ''}"
    />
  {/if}
</div>

<style lang="less">
  .caption {
    padding: 12px;
    overflow-y: auto;
    .high-light {
      color: red;
    }
  }
  @keyframes widthVariation {
    0% {
      width: 177px;
    }
    50% {
      width: 150px;
    }
    100% {
      width: 177px;
    }
  }
  @keyframes opacityVariation {
    0% {
      opacity: 1;
    }
    50% {
      opacity: 0.8;
    }
    100% {
      opacity: 1;
    }
  }
  .human-container {
    position: relative;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 91px;
    height: 375px;
    .human-ins {
      width: 250px;
      height: 375px;
      z-index: 2;
    }
    .light {
      width: 170px;
      height: 220px;
      z-index: 3;
      margin-top: -220px;
      animation:
        widthVariation 3s infinite,
        opacityVariation 4s infinite;
    }
    .stage {
      position: absolute;
      bottom: -25px;
      width: 115px;
      height: 31px;
      z-index: 1;
    }
  }
</style>
